package afcepf.atod18.frameworkMVC2.servlet;

import javax.servlet.*;
import javax.servlet.http.*;

import org.apache.log4j.Logger;





import java.io.*;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

public class ActionServlet extends HttpServlet {
    private static final Logger logger = Logger.getLogger(XMLParser.class);

    private static final long serialVersionUID = 8024973370074930626L;
    
    private static final String ACTION_IDENTIFIER = ".perform";
    
    private XMLParser xmlParser;
    
    private static final FormGenerator formGenerator = new FormGenerator();
    
    public ActionServlet() throws MVC2Exception, IOException {
        super();
        logger.info("-------------------- ActionServler:Constructor: begin --------------------");
        logger.info("ActionServler:Constructor:init FormGenerator ");
        
        formGenerator.searchHMTL();

        /*
         *  demonstrator on in-memory compiler
         *  and class loader
         *    
         *      Class<?> CompileJavaSource.Compile( JavaFileName, JavaSourceCode as String )
         *      the returned class is already loaded
         */
        /*
        logger.info("ActionServler:Constructor:init invoke compiler");
        StringWriter sw = new StringWriter();
        PrintWriter out = new PrintWriter(sw);
        out.println("package form;");
        out.println("public class MonPojo {");
        out.println("   private String name;");
        out.println("   public void setName(String s) {");
        out.println("      name= s;");
        out.println("   }");
        out.println("}");
        out.close();
        Class<?> aClass = CompileJavaSource.Compile("form.MonPojo", sw.toString());
        
        try {
            logger.info("Finding Method");
            Method m = aClass.getMethod("setName", new Class[]{String.class});
            logger.info("Invoking Method");
            m.invoke(aClass.newInstance(), "titi");
        } catch (NoSuchMethodException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SecurityException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InstantiationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        */

        logger.info("ActionServler:Constructor:init XmlParser");
        xmlParser = new XMLParser();
        xmlParser.initialize();
        logger.info("-------------------- ActionServler:Constructor: end --------------------");
    }
    
    /* (non-Javadoc)
     * @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
     */
    @SuppressWarnings("unchecked")
    @Override
    protected void doPost(HttpServletRequest paramReq,
            HttpServletResponse paramResp) throws ServletException, IOException {
        final String HEADER_REFERER = "referer";
        
        logger.info("-------------------- ActionServler:doPost: begin --------------------");
       // getServletPath contains the package name and the class name,
        // as follows /package_name/class_name.perform
        // so 1st, check if URL finish by .perform
        //         if ok, remove .perform from end of URL
        //         try to invoke execute method of desired package/class
        logger.info( "ActionServlet:doPost: getServletPath " +paramReq.getServletPath());
        Enumeration<String> headerNames = paramReq.getHeaderNames();
        if (headerNames == null )
            logger.info("ActionServlet: HeaderNames: no header detected");
        while (headerNames.hasMoreElements()) {
            String headerName = headerNames.nextElement(); 
            logger.info( "ActionServlet:HeaderNames: HeaderName "+headerName + " value "+paramReq.getHeader(headerName));
            if (headerName.contentEquals(HEADER_REFERER)) {
                // referer found
                String referer = paramReq.getHeader(HEADER_REFERER);
                logger.info("ActionServlet:HeaderNames: REFERER found in header: "+referer);
                if (referer.toLowerCase().contains(".hmtl")) {
                    // find caller HMTL page
                    logger.info("ActionServlet:HeaderNames: Caller HTML file found: "+referer );
                }
                else {
                    logger.info("ActionServlet:HeaderNames: No Caller HTML file found: perhaps index.html?" );
                }
            }
        }
        // Retrieve Action class and associated Form class 
        // Create instance of form class
        // Populate form
        // Invoke validateForm of Form class
        // if return is true
        //    invoke execute method of Action class
        // otherwise
        //    populate HTML file with correct fields of form
        //    go to new generated HTML file
        String neededClass = paramReq.getServletPath();
        if (neededClass.endsWith(ACTION_IDENTIFIER)) {
            neededClass = neededClass.replace(ACTION_IDENTIFIER, "");
            if (neededClass.startsWith("/"))
                neededClass = neededClass.substring(1);
            // replace all / by .
            neededClass = neededClass.replace("/", ".");
            
            // find action class
            if (Builder.getInstance().getActions().containsKey(neededClass)) {
                BuilderAction ba = Builder.getInstance().getActions().get(neededClass);
                logger.info("ActionServlet:doPost: find associated form name "+ba.getFormName());
                logger.info("ActionServlet:doPost: find associated form class "+ Builder.getInstance().getRegistryForms().get(ba.getFormName()).getName());
                Object form = null;
                FormGenerator_Form formInfo = null;
                try {
                    // create instance of associated form class
                    form = Builder.getInstance().getNewInstanceOfForm(ba.getFormName());
                    // retrieve information about this form collected by FormGenerator class at servlet start
                    formInfo = formGenerator.getForms().get(ba.getFormName().toLowerCase());
                    if (formInfo!=null) {
                        // we got the URL of the HTML file containing the form
                        //   so we can use it to refill file with good values of fields, for user completion
                        logger.info("ActionServlet:doPost: form called from URL "+formInfo.getUrl());
                    }
                } catch (InstantiationException | IllegalAccessException
                        | MVC2Exception e1) {
                    logger.error( "ActionServlet:doPost: FAIL to instanciate class " +ba.getFormName());
                    e1.printStackTrace();
                }
                try {
                    // populate fields of instance of form class
                    Map<String, String> goodFields = new HashMap<String,String>();
                    Map<String, String> badFields = new HashMap<String,String>();
                    int result =Builder.getInstance().populateBean( Builder.getInstance().getRegistryForms().get(ba.getFormName()), 
                                                        form, 
                                                        paramReq.getParameterMap(), 
                                                        false,
                                                        goodFields,
                                                        badFields);
                    if (result == Builder.BUILDER_POPULATE_BADVALUES) {
                        // we need to populate HTML file with good values of fields and to
                        // let the user filling bad fields
                        String returnPath = formGenerator.FillFields(formInfo, goodFields, paramReq.getContextPath());
                        paramReq.getRequestDispatcher(returnPath).forward(paramReq, paramResp);
                        return;
                    }
                } catch (MVC2Exception e1) {
                    logger.error( "ActionServlet:doPost: FAIL to populate instance of class " +ba.getFormName());
                    e1.printStackTrace();
                }
                try {
                    // invoke validateForm method of form class
                    boolean result = Builder.getInstance().invokeValidateFormMethod(ba.getFormName(), form, true);
                    if (!result) {
                        // form validation fail
                    }
                } catch (MVC2Exception e) {
                   logger.error( "ActionServlet:doPost: FAIL to invoke validateMethod of class " +ba.getFormName());
                   e.printStackTrace();
                }
            }
            
           // invoke execute method of Action class
            logger.info( "ActionServlet:doPost: invoke " +neededClass);
            try {
                String returnPath = Builder.getInstance().invokeExecuteMethod(neededClass, true, paramReq, paramResp);
                if (returnPath != null) {
                    paramReq.getRequestDispatcher(returnPath).forward(paramReq, paramResp);
                }
            } catch (MVC2Exception e) {
                logger.error( "ActionServlet:doPost: FAIL to invoke " +neededClass);
                e.printStackTrace();
            }
        }
        else
            logger.error( "ActionServlet:doPost: called action must be terminated by" +ACTION_IDENTIFIER);
        logger.info("-------------------- ActionServler:doPost: end --------------------");
    }

    /* (non-Javadoc)
     * @see javax.servlet.http.HttpServlet#doPost(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
     */
    @Override
    protected void doGet(HttpServletRequest paramReq,
            HttpServletResponse paramResp) throws ServletException, IOException {
        logger.error( "ActionServlet:doGet: --> forward to doPost");
        doPost( paramReq, paramResp);
    }


}
